package com.eh.excel;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by David Li on 2016/11/28.
 */
public class ReadableExcelHandler<T> extends AbstractExcelHandler implements ExcelHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private Workbook workbook;

    @Override
    public List<T> read(ReadableExcelEvent excelEvent) {
        String filePath = excelEvent.getFilePath();
        String tableName = excelEvent.getTableName();
        workbook = getWorkbook(filePath);

        List<Map<String, Object>> list = parseExcel(workbook, tableName, excelEvent.getFirstLine(), excelEvent.getLastLine(), excelEvent.getSheetIndex());
        // 获取class
        Map<Integer, String> sheets = PropertiesReadUtil.getSheets(tableName);
        List<T> data = Lists.newArrayList();
        try {
            data = convert2Bean(list, (Class<T>) Class.forName(sheets.get(excelEvent.getSheetIndex())));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return data;
    }

    private List<T> convert2Bean(List<Map<String, Object>> data, Class<T> clazz) {
        List<T> result = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(data)) {
            for (Map<String, Object> m : data) {
                T t = null;
                try {
                    t = clazz.newInstance();
                } catch (Exception e) {
                    logger.error("Error occurs when Map transfer to Bean.");
                }
                for (Map.Entry<String, Object> e : m.entrySet()) {
                    try {
                        PropertyDescriptor propertyDescriptor = BeanUtilsBean.getInstance().getPropertyUtils().getPropertyDescriptor(t, e.getKey());
                        if (propertyDescriptor != null) {
                            BeanUtils.setProperty(t, e.getKey(), e.getValue());
                        }
                    } catch (Exception ex) {
                        logger.error("Error occurs when T transfer to PropertyDescriptor.");
                    }
                    result.add(t);
                }
            }
        }
        return result;
    }

    private List<Map<String, Object>> parseExcel(Workbook workbook, String tableName, Integer firstLine, Integer lastLine, Integer sheetIndex) {
        List<Map<String, Object>> result = Lists.newArrayList();
        if (workbook != null) {
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            if (sheet == null) {
                logger.error(String.format("sheet[%d]不存在", sheetIndex));
            }

            Map<Integer, String> headers = PropertiesReadUtil.getColumns(tableName);
            List<Integer> headerIndexes = Lists.newArrayList(headers.keySet());
            //循环除了第一行的所有行
            for (int rowNum = firstLine; rowNum <= lastLine; rowNum++) {
                Map<String, Object> map = Maps.newHashMap();
                //获得当前行
                Row row = sheet.getRow(rowNum);
                if (row == null) {
                    continue;
                }
                //获得当前行的开始列
                int firstCellNum = row.getFirstCellNum();
                //获得当前行的列数
                int lastCellNum = row.getPhysicalNumberOfCells();
                //循环当前行
                for (int cellNum = 0; cellNum < lastCellNum - firstCellNum; cellNum++) {
                    if (!headerIndexes.contains(cellNum)) {
                        continue;
                    }
                    Cell cell = row.getCell(cellNum);
                    map.put(headers.get(cellNum), getCellValue(cell));
                }
                result.add(map);
            }
        }
        return result;
    }

    private Object getCellValue(Cell cell) {
        Object value = null;
        if (cell == null) {
            return value;
        }
        //把数字当成String来读，避免出现1读成1.0的情况
        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }

        //判断数据的类型
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_NUMERIC: //数字
                // 时间格式处理
                if (DateUtil.isCellDateFormatted(cell)) {
                    value = cell.getDateCellValue();
                    break;
                }
                value = cell.getNumericCellValue();
                break;
            case Cell.CELL_TYPE_STRING: //字符串
                value = cell.getStringCellValue();
                break;
            case Cell.CELL_TYPE_BOOLEAN: //Boolean
                value = cell.getBooleanCellValue();
                break;
            case Cell.CELL_TYPE_FORMULA: //公式
                value = cell.getCellFormula();
                break;
            case Cell.CELL_TYPE_BLANK: //空值
                value = "";
                break;
            case Cell.CELL_TYPE_ERROR: //故障
                logger.error(String.format("Cell[%d, %d] 产生故障！", cell.getRowIndex(), cell.getColumnIndex()));
                break;
            default:
                logger.error(String.format("Cell[%d, %d] 未知类型！", cell.getRowIndex(), cell.getColumnIndex()));
                break;
        }
        return value;
    }
}
